package com.zhdl.network.modbus;


import com.project.common.util.ByteHelper;
import com.project.common.util.CRC16;
import com.zhdl.network.modbus.request.WriteSingleKeepRegisterReq;

import java.io.ByteArrayOutputStream;
import java.io.IOException;

/**
 * 组装modbus-RTU响应数据包
 */
public class ModbusRtuRespPkg {

    /**
     * int整数转换为4字节的byte数组 小端模式
     *
     * @param i 整数
     * @return byte数组
     */
    public static byte[] intToByte4(int i) {
        byte[] targets = new byte[4];
        targets[1] = (byte) (i & 0xFF);
        targets[0] = (byte) (i >> 8 & 0xFF);
        targets[3] = (byte) (i >> 16 & 0xFF);
        targets[2] = (byte) (i >> 24 & 0xFF);
        return targets;
    }

    /**
     * TCP MBAP 7字节报文头封装
     *
     * @param unitBuff
     * @return
     * @throws IOException
     */
    private static byte[] PkgFullFrame(byte[] unitBuff) throws IOException {
        ByteArrayOutputStream bw = new ByteArrayOutputStream();
        // 传输标识符 2HEX
        bw.write((byte) 0x00);
        bw.write((byte) 0x00);
        // 协议标识符 2HEX
        bw.write((byte) 0x00);
        bw.write((byte) 0x00);
        // 长度 2HEX 高字节在前
        short length = (short) (unitBuff.length + 1);
        bw.write((byte) ((length & 0xFF00)) >> 8); // DataNum(H)
        bw.write((byte) (length & 0x00FF)); // DataNum(L)
        // 站标识 目前固定为 0x01
        // 具体指令的数据单元部分
        bw.write(0x01); // DataNum(L)
        bw.write(unitBuff);

        return bw.toByteArray();
    }

    /**
     * 0x06 写单个寄存器 rtu 协议下
     *
     * @param req
     */
    public static byte[] WriteSingleKeepRegister(WriteSingleKeepRegisterReq req) throws IOException {
        ByteArrayOutputStream bw = new ByteArrayOutputStream();

        byte[] bsTemp;
        bw.write((byte)Integer.parseInt(req.id));
        // 功能码 1HEX
        bw.write((byte) 0x06);
        // 起始地址 2HEX 0x0000 至 0xFFFF
        bsTemp = ByteHelper.stringToBytes(req.startAddr);

        bw.write(bsTemp);
        // 寄存器值
        bsTemp = ByteHelper.stringToBytes(req.writeValue);
        bw.write(bsTemp);

        bsTemp = bw.toByteArray();
        byte[] calcBytes = new byte[bsTemp.length];
        System.arraycopy(bsTemp, 0, calcBytes, 0, calcBytes.length);
        byte[] crc = CRC16.MODBUS(calcBytes);
        bw.write(crc);
        return bw.toByteArray();
    }

    /**
     * 0x03 读多个寄存器 rtu 协议下
     *
     * @param req
     */
    public static byte[] ReadSingleKeepRegister(WriteSingleKeepRegisterReq req) throws IOException {
        ByteArrayOutputStream bw = new ByteArrayOutputStream();

        byte[] bsTemp;
        //bw.write(ByteHelper.stringToBytes(req.id));
        bw.write((byte) Integer.parseInt(req.id));
        // 功能码 1HEX
        bw.write((byte) 0x03);
        // 起始地址 2HEX 0x0000 至 0xFFFF
        bsTemp = ByteHelper.stringToBytes(req.startAddr);

        bw.write(bsTemp);
        // 寄存器值
        bsTemp = ByteHelper.stringToBytes(req.writeValue);
        bw.write(bsTemp);

        bsTemp = bw.toByteArray();
        byte[] calcBytes = new byte[bsTemp.length];
        System.arraycopy(bsTemp, 0, calcBytes, 0, calcBytes.length);
        byte[] crc = CRC16.MODBUS(calcBytes);
        bw.write(crc);
        return bw.toByteArray();
    }

    /**
     * 0x06 写单个线圈寄存器 rtu协议下
     * 设定工作模式为原点模式: 0x3500   0x6
     * 发送: 01 06 35 00 00 06 06 04
     *
     * @param req
     */
    public static byte[] WriteSingleKeepRegister06(WriteSingleKeepRegisterReq req) throws IOException {

        ByteArrayOutputStream bw = new ByteArrayOutputStream();

        byte[] bsTemp;

        bw.write((byte) Integer.parseInt(req.id));
        // 功能码 1HEX
        bw.write((byte) 0x06);
        //单个线圈寄存器地址 0x3500
        bsTemp = ByteHelper.hexString2Bytes(req.startAddr);
        bw.write(bsTemp);

        //修改寄存器的值位 00 06
        bsTemp = ByteHelper.hexString2Bytes(req.writeValue);
        bw.write(bsTemp);

        bsTemp = bw.toByteArray();
        byte[] calcBytes = new byte[bsTemp.length];
        System.arraycopy(bsTemp, 0, calcBytes, 0, calcBytes.length);
        byte[] crc = CRC16.MODBUS(calcBytes);
        bw.write(crc);
        return bw.toByteArray();
    }

    /**
     * 0x10 读多个寄存器 rtu 协议下
     *
     * @param req
     */
    public static byte[] WriteMoreKeepRegister(WriteSingleKeepRegisterReq req) throws IOException {
        ByteArrayOutputStream bw = new ByteArrayOutputStream();

        byte[] bsTemp;
        //bw.write(ByteHelper.hexString2Bytes(req.id));
        bw.write((byte) Integer.parseInt(req.id));
        // 功能码 1HEX
        bw.write((byte) 0x10);
        // 起始地址 2HEX 0x0000 至 0xFFFF
        bsTemp = ByteHelper.hexString2Bytes(req.startAddr);
        bw.write(bsTemp);

        short word = (short) (req.writeValue.length() / 4);
        bw.write(ByteHelper.shortToByteArrayByHigh(word));
        //数据长度
        bw.write(req.writeValue.length() / 2);
        // 寄存器值
        bsTemp = ByteHelper.hexString2Bytes(req.writeValue);
        bw.write(bsTemp);

        bsTemp = bw.toByteArray();
        byte[] calcBytes = new byte[bsTemp.length];
        System.arraycopy(bsTemp, 0, calcBytes, 0, calcBytes.length);
        byte[] crc = CRC16.MODBUS(calcBytes);
        bw.write(crc);
        return bw.toByteArray();
    }

}
